package com.lsj.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lsj.common.constant.ProductConstant;
import com.lsj.gulimall.product.dao.CategoryBrandRelationDao;
import com.lsj.gulimall.product.entity.CategoryBrandRelationEntity;
import com.lsj.gulimall.product.vo.CategoryThreeVo;
import com.lsj.gulimall.product.vo.CategoryTwoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lsj.common.utils.PageUtils;
import com.lsj.common.utils.Query;

import com.lsj.gulimall.product.dao.CategoryDao;
import com.lsj.gulimall.product.entity.CategoryEntity;
import com.lsj.gulimall.product.service.CategoryService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Resource
    CategoryBrandRelationDao categoryBrandRelationDao;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> listWithTree() {
        // 查出所有数据
        List<CategoryEntity> entities = baseMapper.selectList(null);
        // 组装成树形结构
        List<CategoryEntity> data = entities.stream().filter((categoryEntity -> {
                    return categoryEntity.getParentCid() == 0;
                })
        ).map((categoryEntity -> {
            categoryEntity.setChildren(getNextCategory(categoryEntity, entities));
            return categoryEntity;
        })).collect(Collectors.toList());
        return data;
    }

    /**
     * 跟新三级分类表同时更新分类品牌关系表
     * @param category
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDetail(CategoryEntity category) {
        this.baseMapper.updateById(category);
        if (!StringUtils.isEmpty(category.getName())) {
            QueryWrapper<CategoryBrandRelationEntity> wrapper = new QueryWrapper<>();
            CategoryBrandRelationEntity categoryBrandRelationEntity = new CategoryBrandRelationEntity();
            wrapper.eq("catelog_id",category.getCatId());
            categoryBrandRelationEntity.setCatelogName(category.getName());
            categoryBrandRelationDao.update(categoryBrandRelationEntity,wrapper);
        }
    }

    /**
     * 查出所有的一级分类
     * @return
     */
    @Override
    public List<CategoryEntity> getCategoryLevel1() {
        List<CategoryEntity> categoryEntities = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("cat_level", ProductConstant.CategoryEnum.CATEGORY_ONE.getCode()));
        return categoryEntities;
    }


    @Override
    public Map<String, List<CategoryTwoVo>> getCatalogJson(){
        // 给缓存中放入json字符串，拿出的json字符串，还要逆转为能用的对象类型；【序列化与反序列化】
        /**
         * 1、空结果缓存：解决缓存穿透
         * 2、设置过期时间（加随机值）：解决缓存雪崩
         * 3、加锁：解决缓存击穿
         */
        // 1、加入缓存逻辑，缓存中的数据是json字符串。
        // JSON跨语言，跨平台兼容
        String catalogJSON = redisTemplate.opsForValue().get("catalogJSON");
        if (StringUtils.isEmpty(catalogJSON)) {
            // 缓存中没有查询数据库
            Map<String, List<CategoryTwoVo>> catalogJsonFromDb = getCatalogJsonFromDb();
            // 查到的数据再放入缓存，将对象转为json放在缓存中
            String jsonString = JSON.toJSONString(catalogJsonFromDb);
            // 设置数据的过期时间为一天用于解决缓存雪崩问题
            redisTemplate.opsForValue().set("catalogJSON",jsonString,1, TimeUnit.DAYS);
            return catalogJsonFromDb;
        }
        // 转为我们指定的对象
        Map<String, List<CategoryTwoVo>> result = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<CategoryTwoVo>>>() {
        });
        return result;
    }

    /**
     * 从数据库中查询并封装分类数据
     * @return
     */
    private Map<String, List<CategoryTwoVo>> getCatalogJsonFromDb() {
        // 一次性获取所有的分类数据
        List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
        Map<String, List<CategoryTwoVo>> map = new HashMap<>();
        // 获取一级分类
        List<CategoryEntity> level1s = getCategorysByParentId(categoryEntities, ProductConstant.CategoryEnum.CATEGORY_PARENT.getCode().longValue());
        if (level1s != null) {
            map = level1s.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
                // 获取一级分类下的二级分类
                List<CategoryEntity> level2s = getCategorysByParentId(categoryEntities, v.getCatId());
                List<CategoryTwoVo> categoryTwoVos = null;
                if (level2s != null) {
                    categoryTwoVos = level2s.stream().map(level2 -> {
                        CategoryTwoVo categoryTwoVo = new CategoryTwoVo();
                        categoryTwoVo.setCatalog1Id(v.getCatId().toString());
                        categoryTwoVo.setId(level2.getCatId().toString());
                        categoryTwoVo.setName(level2.getName());
                        // 获取二级分类下的三级分类
                        List<CategoryEntity> level3s = getCategorysByParentId(categoryEntities, level2.getCatId());
                        List<CategoryThreeVo> categoryThreeVos = null;
                        if (level3s != null) {
                            categoryThreeVos = level3s.stream().map(level3 -> {
                                CategoryThreeVo categoryThreeVo = new CategoryThreeVo();
                                categoryThreeVo.setCatalog2Id(level2.getCatId().toString());
                                categoryThreeVo.setId(level3.getCatId().toString());
                                categoryThreeVo.setName(level3.getName());
                                return categoryThreeVo;
                            }).collect(Collectors.toList());
                        }
                        categoryTwoVo.setCatalog3List(categoryThreeVos);
                        return categoryTwoVo;
                    }).collect(Collectors.toList());
                }
                return categoryTwoVos;
            }));
        }
        return map;
    }

    /**
     * 根据父类id获取相应的分类
     * @param list
     * @param parent_id
     * @return
     */
    private List<CategoryEntity> getCategorysByParentId(List<CategoryEntity> list, Long parent_id) {
        return list.stream().filter(item -> {
            return item.getParentCid().longValue() == parent_id.longValue();
        }).collect(Collectors.toList());
    }

    public List<CategoryEntity> getNextCategory(CategoryEntity parentCategory, List<CategoryEntity> list) {
        List<CategoryEntity> data = list.stream().filter(categoryEntity -> {
            return categoryEntity.getParentCid().equals(parentCategory.getCatId());
        }).map(categoryEntity -> {
            categoryEntity.setChildren(getNextCategory(categoryEntity, list));
            return categoryEntity;
        }).collect(Collectors.toList());
        return data;
    }

}